import { 
  AxesHelper,
  HemisphereLight,
  Mesh,
  PerspectiveCamera, 
  Scene, 
  WebGLRenderer,
  Material,
  DoubleSide,
  BoxGeometry,
  MeshStandardMaterial,
  AmbientLight,
  SpotLight,
  SpotLightHelper,
  SphereGeometry,
  MeshLambertMaterial,
  CylinderBufferGeometry,
  MeshToonMaterial,
  Vector3,
  Raycaster,
  Geometry,
  MeshBasicMaterial,
  TubeGeometry,
  CatmullRomCurve3,
} from "three"
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import stats from '../utils/stats'

let scene = new Scene()
const camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000)
// 不能设置为0
camera.position.set(-30, 40, 30)
camera.lookAt(scene.position)

const renderer = new WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setClearColor(0x000000)
renderer.setSize(window.innerWidth, window.innerHeight)

document.body.appendChild(renderer.domElement)


// 添加坐标系
const axes = new AxesHelper(10)
scene.add(axes)

// 添加环境光
const ambientLight = new AmbientLight(0x333333)
scene.add(ambientLight)

// 添加聚光灯
let spotLight = new SpotLight('#ffffff')
spotLight.position.set(-40, 60, -10)
spotLight.castShadow = true
spotLight.shadow.camera.near = 1
spotLight.shadow.camera.far = 100
scene.add(spotLight)
// scene.add(new SpotLightHelper(spotLight))

// add cube
let cubeGeometry = new BoxGeometry(4, 4, 4)
let cubeMaterial = new MeshStandardMaterial({color: 0xff0000})
let cube = new Mesh(cubeGeometry, cubeMaterial)
cube.castShadow = true
cube.position.set(-10, 4, 0)
scene.add(cube)

// 添加球
let sphereGeom = new SphereGeometry(2, 20, 20)
let sphereMate = new MeshLambertMaterial({color: 0x00ff00})
let sphere = new Mesh(sphereGeom, sphereMate)
sphere.position.set(20, 0, 0)
sphere.castShadow = true
scene.add(sphere)

// 添加圆柱
let cylinderGeom = new CylinderBufferGeometry(2, 2, 5)
let cylinderMate = new MeshToonMaterial({color: 0x77ff77})
let cylinder = new Mesh(cylinderGeom, cylinderMate)
cylinder.castShadow = true
cylinder.position.set(0, 1, 0)
scene.add(cylinder);

const control = {
  showRay: true,
}

// 交互选择功能
document.addEventListener('mousedown', onDocumentMouseDown, false)
document.addEventListener('mousemove', onDocumentMouseMove, false)

function onDocumentMouseDown(evt: MouseEvent) {
  console.log('down')
  let vector = new Vector3(
    evt.clientX / window.innerWidth * 2 -1,
    -(evt.clientY / window.innerHeight) * 2 + 1,
    0.5
  );

  vector = vector.unproject(camera);
  // 从屏幕上的点击位置向场景发射一束光束
  let raycaster = new Raycaster(camera.position, vector.sub(camera.position).normalize());
  // 判断指定对象有没有被光束击中
  let intersects = raycaster.intersectObjects([sphere, cylinder, cube]);

  if (intersects.length > 0) {
    let mesh = intersects[0].object as Mesh<Geometry, Material>
    let transparent = mesh.material.transparent

    if (transparent) {
      mesh.material.transparent = false;
      mesh.material.opacity = 1;
    } else {
      mesh.material.transparent = true;
      mesh.material.opacity = 0.1;
    }
  }
}

let tube: Mesh

function onDocumentMouseMove(evt: MouseEvent) {
  if (control.showRay) {
    let vector = new Vector3(
      evt.clientX / window.innerWidth * 2 -1,
      -(evt.clientY / window.innerHeight) * 2 + 1,
      0.5
    );
  
    vector = vector.unproject(camera);

    let raycaster = new Raycaster(camera.position, vector.sub(camera.position).normalize());
    let intersects = raycaster.intersectObjects([sphere, cylinder, cube]);
    
    if (intersects.length > 0) {
      let points = [];
      points.push(new Vector3(-30, 39.8, 30));
      points.push(intersects[0].point);

      let mat = new MeshBasicMaterial({
        color: 0xff0000, 
        transparent: true,
        opacity: 0.6
      });
      let tubeGeometry = new TubeGeometry(new CatmullRomCurve3(points), 60, 0.001);

      if (tube) scene.remove(tube)

      if (control.showRay) {
        tube = new Mesh(tubeGeometry, mat);
        scene.add(tube)
      }
    }
  }
}


// new OrbitControls(camera, renderer.domElement)

function render(time: number): void {
  time *= 0.001
  stats.update()

  // 矩形动画
  cube.rotation.x += 0.01
  cube.rotation.y += 0.01
  cube.rotation.z += 0.01

  // 球动画
  sphere.position.x = 20 + (10 * Math.cos(time))
  sphere.position.y = 2 + (10 * Math.abs(Math.sin(time)))

  // 
  let scaleX = Math.abs(Math.sin(time))
  let scaleY = Math.abs(Math.cos(time))
  let scaleZ = Math.abs(Math.sin(time))
  cylinder.scale.set(scaleX, scaleY, scaleZ)

  requestAnimationFrame(render)
  renderer.render(scene, camera)
}

requestAnimationFrame(render)